import d3 from 'd3';
import _ from 'underscore';
import circosJs from 'nicgirault/circosJs';

import Grapher from './grapher';
import * as Helpers from './visualisation_helpers';

class Graph {
  static name() {
    return 'Circos';
  }

  static className() {
    return 'circos-distribution collapse in';
  }

  static collapseId(props) {
    return 'circos-collapse';
  }

  static dataName(props) {
      return 'Circos-visualisation';
  }

  constructor($svgContainer, props) {
    this.queries = props.queries;
    this.svgContainer = $svgContainer;
    this.seq_type = Helpers.get_seq_type(props.program);
    this.initiate();
  }

  initiate() {
    // this.width = 700;
    this.width = this.svgContainer.width();
    this.height = 600;
    this.innerRadius = 200;
    this.outerRadius = 230;
    this.query_arr = [];
    this.hit_arr = [];
    this.layout_arr = [];
    this.chords_arr = [];
    // this.max_length = 0;
    this.hsp_count = 50;
    this.denominator = 100;
    this.spacing = 20;
    this.labelSpacing = 10;
    var suffixes = {amino_acid: 'aa', nucleic_acid: 'bp'};
    this.construct_layout();
    this.iterator_for_edits();
    this.hit_arr = _.uniq(this.hit_arr);
    this.handle_spacing();
    var prefix = d3.formatPrefix(this.max_length);
    this.suffix = ' '+prefix.symbol+suffixes[this.seq_type.subject_seq_type];
    if (prefix.symbol == 'k') {
      this.denominator = 1000;
    } else if (prefix.symbol == 'M') {
      this.denominator = 1000000;
      this.spacing = 1000000;
      this.labelSpacing = 200000;
    } else if (prefix.symbol == 'g') {
      this.denominator = 1000000000;
    }
    d3.select(this.svgContainer[0]).insert('svg',':first-child')
        .attr('class','circosContainer');
    this.create_instance(this.svgContainer, this.width, this.height);
    if (this.chords_arr.length && this.layout_arr.length) {
      this.instance_render();
    } else {
      this.render_error();
    }
    this.setupTooltip();
    // this.drawLegend();
  }

  iterator_for_edits() {
    this.max_length = this.calculate_max_length();
    if (this.hit_arr.length > 10) {
      this.complex_layout_edits();
    }
  }

  // Generate both layout_arr and chords_arr with top hsps set by this.hsp_count
  construct_layout() {
    var hsp_count = 0;
    var query_count = 0;
    var num_karyotype = 32;
    var num_queries = this.queries.length;
    var x = Math.min(num_karyotype / 2, num_queries);
    var num_hits = (num_karyotype - x) / x;
    this.new_layout = [];
    this.data = _.map(this.queries, _.bind(function (query) {
      if (query_count < x) {
        var label = query.id;
        var len = query.length;
        var item1 = {'len': len, 'color': '#8dd3c7', 'label': label, 'id': 'Query_'+this.clean_id(query.id), 'ori_id': label};
        this.layout_arr.push(item1);
        var hit_details = _.map(query.hits, _.bind(function(hit) {
          if (hit.number < num_hits) {
            var hsp_details = _.map(hit.hsps, _.bind(function (hsp) {

              if (_.indexOf(this.hit_arr, hit.id) == -1) {
                var label = hit.id;
                var len  = hit.length;
                this.hit_arr.push(hit.id);
                var item2 = {'len': len, 'color': '#80b1d3', 'label': label, 'id': 'Hit_'+this.clean_id(hit.id), 'ori_id': label};
                this.layout_arr.push(item2);
              }

              var item3 = ['Query_'+this.clean_id(query.id), hsp.qstart, hsp.qend, 'Hit_'+this.clean_id(hit.id), hsp.sstart, hsp.send, hit.number, hsp];
              this.chords_arr.push(item3);
              return hsp;
            }, this));
            return hit;
          }
        }, this));
      }
      this.query_arr.push(query.id);
      return query;
    }, this));
  }

  // rearraging hit and query karyotypes to have all query in one place
  rearrange_new_layout() {
    _.each(this.new_layout, _.bind(function(obj) {
      var id = (obj.id).slice(0,3);
      if (id == 'Que') {
        this.layout_arr.push(obj);
      }
    }, this));
    _.each(this.new_layout, _.bind(function(obj) {
      var id = (obj.id).slice(0,3);
      if (id == 'Hit') {
        this.layout_arr.push(obj);
      }
    }, this));
  }

  // label edits along with deleting hits which are too small to display
  complex_layout_edits() {
    this.delete_from_layout = [];
    this.delete_from_chords = [];
    _.each(this.layout_arr, _.bind(function (obj, index) {
      var rel_length = (obj.len / this.max_length).toFixed(3);
      var label = obj.label;
      if (rel_length < 0.1 && (obj.id).slice(0,3) != 'Que') {
        this.delete_from_layout.push(obj);
        this.hit_arr.slice(_.indexOf(this.hit_arr, obj.label), 1); // corresponding delete from hit_arr
      }
    }, this));
  }

  // get the chords_arr index based on hit or query id
  check_in_chords_arr(id, type, index) {
    var count = 0;
    _.each(this.chords_arr, _.bind(function (obj) {
      if (type == 'Que') {
        if (obj[0] != id) {
          count++
        }
      }
    }, this))
    if (count == this.chords_arr.length) {
      console.log('no record found '+id);
      this.delete_arr.push(index);
    }
  }

  // get index of hit_arr based on id
  find_index_of_hit(id) {
    var found;
    _.each(this.queries, _.bind(function (query) {
      _.each(query.hits, _.bind(function(hit) {
        var check_id = 'Hit_'+this.clean_id(hit.id)
        if (id == check_id) {
          found = hit.id;
        }
      }, this))
    }, this));
    return _.indexOf(this.layout_arr, found);
  }

  edit_labels() {
    console.log('label edits');
    _.each(this.layout_arr, _.bind(function (obj) {
      var rel_length = (obj.len / this.max_length).toFixed(3);
      var label = obj.label;
      if (rel_length < 0.41) {
        obj.label = '..';
      } else if (label.length > 10) {
        obj.label = label.slice(0,2) + '...';
      } else {
        obj.label = obj.ori_id;
      }
    }, this));
  }

  calculate_multipliers() {
    var sum_query_length = 0;
    var sum_hit_length = 0;
    _.each(this.query_arr, _.bind(function (id) {
      _.each(this.data, _.bind(function (query) {
        if (id == query.id) {
          sum_query_length += query.length;
        }
      }, this));
    }, this));

    _.each(this.data, _.bind(function (query) {
      _.each(query.hits, _.bind(function (hit) {
        var index = _.indexOf(this.hit_arr, hit.id);
        if (index >= 0) {
          sum_hit_length += hit.length;
        }
      }, this));
    }, this));
    var mid_sum = (sum_query_length + sum_hit_length) / 2;
    console.log('mid sum '+mid_sum+' hit_sum '+sum_hit_length+' query_sum '+sum_query_length);
    this.query_multiplier = (mid_sum / sum_query_length).toFixed(3);
    this.hit_multiplier = (mid_sum / sum_hit_length).toFixed(3);
    console.log('query '+this.query_multiplier+' hit '+this.hit_multiplier);
  }

  handle_spacing() {
    if (this.max_length > 16000) {
      this.spacing = 200;
    } else if (this.max_length > 12000) {
      this.spacing = 150;
    } else if (this.max_length > 8000) {
      this.spacing = 100;
    } else if (this.max_length > 4000) {
      this.spacing = 75;
    } else if (this.max_length > 1800) {
      this.spacing = 50;
    }
  }

  calculate_max_length() {
    var max = 0;
    _.each(this.layout_arr, function(obj) {
      if (max < obj.len) {
        max = obj.len;
      }
    })
    return max;
  }

  clean_id(id) {
    return id.replace(/[^a-zA-Z0-9]/g, '');
  }

  create_instance(container, width, height) {
    this.instance = new circosJs({
      container: '.circosContainer',
      width: width,
      height: height
    });
    this.chord_layout();
    this.instance_layout();
  }

  chord_layout() {
    if (this.chords_arr.length > 11) {
      this.paletteSize = 11;
    } else {
      this.paletteSize = this.chords_arr.length;
    }
    return {
      usePalette: true,
      colorPaletteSize: this.paletteSize,
      // color: 'rgb(0,0,0)',
      colorPalette: 'RdYlBu', // colors of chords based on last value in chords
      // tooltipContent: 'Hiten',
      opacity: 0.5 // add opacity to ribbons
    }
  }

  instance_layout() {
    return {
      innerRadius: this.innerRadius,
      outerRadius: this.outerRadius,
      cornerRadius: 1, // rounding at edges of karyotypes
      labels: {
        display: true,
        size: '10px',
        radialOffset: 10
      },
      ticks: {
        display: true,
        spacing: this.spacing, // the ticks values to display
        labelSpacing: this.labelSpacing, // ticks value apper in interval
        labelDenominator: this.denominator, // divide the value by this value
        labelSuffix: this.suffix,
        labelSize: '10px',
        majorSpacing: this.labelSpacing, // major ticks apper in interval
        size: {
          minor: 0, // to remove minor ticks
          major: 4
        }
      }
    }
  }

  instance_render() {
    this.instance.layout(this.instance_layout(),this.layout_arr);
    this.instance.chord('chord1',this.chord_layout(),this.chords_arr);
    this.instance.render();
  }

  render_error() {
    this.svgContainer.find('svg').remove();
    this.svg = d3.select(this.svgContainer[0]).insert('svg',':first-child')
        .attr('width', this.svgContainer.width())
        .attr('height', this.svgContainer.height())
        .append('g')
        .attr('class', 'circos-error')
        .attr('transform','translate('+this.svgContainer.width() / 2+','+this.svgContainer.height()/2+')')
        .append('text')
        .attr('text-anchor','start')
        .attr('dy','0.75em')
        .attr('x', -50)
        .attr('y', 2)
        .text('Sorry no Circos generated')
  }

  layoutReset() {
    this.layoutHide = [];
    _.each(this.layout_arr, function(obj) {
      $("."+obj.id).css("opacity", 1);
    });
  }

  chordsReset() {
    this.chordsHide = [];
    _.each(this.chords_arr, function (obj) {
      var slen = obj[1] + obj[2];
      var tlen = obj[4] + obj[5];
      $("#"+obj[0]+"_"+slen+"_"+obj[3]+"_"+tlen).show();
    });
  }

  chordsCheck(id, type) {
    _.each(this.chords_arr, _.bind(function (obj, index) {
      if (type == 'Que') {
        if (obj[0] == id) {
          this.chordsHide.push(index);
          this.layoutHide.push(obj[3]);
        }
      }
      if (type == 'Hit') {
        if (obj[3] == id) {
          this.chordsHide.push(index);
          this.layoutHide.push(obj[0]);
        }
      }
    }, this))
  }

  chordsClean() {
    _.each(this.chords_arr, _.bind(function (obj, index) {
      if (_.indexOf(this.chordsHide, index) == -1) {
        var slen = obj[1] + obj[2];
        var tlen = obj[4] + obj[5];
        $("#"+obj[0]+"_"+slen+"_"+obj[3]+"_"+tlen).hide();
      }
    }, this))
  }

  layoutClean() {
    _.each(this.layout_arr, _.bind(function(obj, index) {
      if(_.indexOf(this.layoutHide, obj.id) == -1) {
        $("."+obj.id).css("opacity",0.1);
      }
    }, this))
  }

  setupTooltip() {
      var selected = {};
      $('.circos-distribution').on('click', _.bind(function(event) {
          event.stopPropagation();
          this.layoutReset();
          this.chordsReset();
          selected = {};
      }, this));
    _.each(this.query_arr, _.bind(function (id, index) {
      this.chordsHide = [];
      this.layoutHide = [];
      if (id) {
        $(".circos-distribution .Query_"+this.clean_id(id)).attr('data-toggle','tooltip')
                      .attr('title',id)
                      .on('click', _.bind(function (event) {
                          event.stopPropagation();
                        if (selected[index] != id) {
                          selected[index] = id;
                          var cleaned_id = "Query_"+this.clean_id(id);
                          this.layoutHide.push(cleaned_id);
                          this.chordsCheck(cleaned_id, "Que");
                          this.chordsClean();
                          this.layoutClean();
                        } else {
                          selected[index] = 0;
                          this.layoutReset();
                          this.chordsReset();
                        }
                      }, this));
      }
    }, this))
    _.each(this.hit_arr, _.bind(function(id, index) {
      this.chordsHide = [];
      this.layoutHide = [];
      if (id) {
        $(".circos-distribution .Hit_"+this.clean_id(id)).attr('data-toggle','tooltip')
                    .attr('title',id)
                    .on('click', _.bind(function (event) {
                        event.stopPropagation();
                      if (selected[index] != id) {
                        selected[index] = id;
                        var cleaned_id = "Hit_"+this.clean_id(id);
                        this.layoutHide.push(cleaned_id);
                        this.chordsCheck(cleaned_id, "Hit");
                        this.chordsClean();
                        this.layoutClean();
                      } else {
                        selected[index] = 0;
                        this.layoutReset();
                        this.chordsReset();
                      }
                    }, this));
      }
    }, this));
    $('[data-toggle="tooltip"]').tooltip({
      'placement': 'top',
      'container': 'body',
      'html': 'true',
      'delay': 0,
      'white-space': 'nowrap'
    });
  }

  ratioCalculate(value, min, max, scope, reverse, logScale) {
    var fraction, scaleLogBase, x;
    scaleLogBase = logScale ? 2.3 : 1;
    if (min === max || (value === min && !reverse) || (value === max && reverse)) {
      return 0;
    }
    if (value === max || (value === min && reverse)) {
      return scope - 1;
    }
    fraction = (value - min) / (max - min);
    x = Math.exp(1 / scaleLogBase * Math.log(fraction));
    if (reverse) {
      x = 1 - x;
    }
    return Math.floor(scope * x);
  }

  drawLegend() {
    this.ratioHSP = [];
    _.each(this.chords_arr, _.bind(function (obj) {
      var item = {number: obj[6], evalue: obj[7].evalue}
      this.ratioHSP.push(item);
    }, this));
    var min = d3.min(this.ratioHSP, function(d) {
      return d.number;
    });
    var max = d3.max(this.ratioHSP, function(d) {
      return d.number;
    });
    console.log('chords_arr '+this.chords_arr.length);
    console.log('ratioHSP test '+this.ratioHSP.length);
    console.log('paletteSize '+this.paletteSize);
    console.log('min '+min+' max '+max);
    this.legend = d3.select(this.svgContainer[0]).insert('svg', ':first-child')
        .attr('height', 20)
        .attr('width', this.ratioHSP.length * 30)
        .attr('transform','translate(10, 10)')
        .append('g')
        .attr('class','RdYlBu')
        .attr('transform','translate(10, 0)');

    var bar = this.legend.selectAll('.bar')
        .data(this.ratioHSP)
        .enter().append('g')
        .attr('class','g')
        .attr('transform', function(d, i) {
          return 'translate('+i * 30+',0)';
        })
        .append('rect')
        .attr('class',_.bind(function(d,i) {
          var s = this.ratioCalculate(d.number,min,max,this.paletteSize, false, false);
          console.log('calc ratio '+s);
          return 'q'+s+"-"+this.paletteSize;
        }, this))
        .attr('data-toggle','tooltip')
        .attr('title', function (d) {
          return d.evalue;
        })
        .attr('x', 1)
        .attr('width', 30)
        .attr('height', 20);
        // .attr('fill','#43ff21');

    var scale = d3.scale.linear()
        .domain([0, 250])
        .range([0, 100]);

    // this.legend.append('rect')
    //     .attr('x', 7*14)
    //     .attr('width', 2*10)
    //     .attr('height', 10)
    //     .attr('fill','#43ff21');
    //
    // this.legend.append('text')
    //     .attr('class','text-legend')
    //     .attr('transform','translate('+10+',0)')
    //     .attr('x',6*14)
    //     .text('Weaker Hits');
    //
    // this.legend.append('text')
    //     .attr('class','text-legend')
    //     .attr('transform','translate('+10+',0)')
    //     .attr('x',9*14)
    //     .text('Stronger Hits');

    // bar.selectAll('rect')


    // this.legend.append('rect')
    //     .attr('x',1)
    //     .attr('width', 10)
    //     .attr('height', 10)
    //     .attr('fill','#232323');
  }
}

var Circos = Grapher(Graph);
export default Circos;
